package com.cloud.pole.admin.service.impl;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import cn.hutool.json.JSONArray;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ace.cache.annotation.Cache;
import com.ace.cache.api.CacheAPI;
import com.cloud.pole.admin.biz.UserBiz;
import com.cloud.pole.admin.controller.AuthController;
import com.cloud.pole.admin.model.entity.User;
import com.cloud.pole.admin.model.vo.FrontUser;
import com.cloud.pole.admin.service.AuthService;
import com.cloud.pole.admin.service.PermissionService;
import com.cloud.pole.api.admin.AdminUserApi;
import com.cloud.pole.api.permission.PermissionApi;
import com.cloud.pole.common.constant.CacheConstant;
import com.cloud.pole.common.constant.CommonConstants;
import com.cloud.pole.common.constant.UserConstant;
import com.cloud.pole.common.exception.BaseException;
import com.cloud.pole.common.exception.auth.UserInvalidException;
import com.cloud.pole.common.util.jwt.IJWTInfo;
import com.cloud.pole.common.util.jwt.JWTInfo;
import com.cloud.pole.common.util.jwt.JwtAuthenticationRequest;
import com.cloud.pole.common.util.jwt.JwtTokenUtil;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class AuthServiceImpl implements AuthService {

    @Autowired
    private PermissionService permissionService;
    @Autowired
    private CacheAPI cacheAPI;
    @Autowired
    private UserBiz userBiz;    
    private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);

    @Override
    public String login(JwtAuthenticationRequest authenticationRequest) throws Exception {
        AdminUserApi info = permissionService.validate(authenticationRequest.getUsername(), authenticationRequest.getPassword());
        if (!StringUtils.isEmpty(info.getUserId())) {
        	JWTInfo jwtInfo = new JWTInfo(info.getUsername(), JWTInfo.USER_TYPE_ADMIN, info.getUserId() + "", info.getName(), info.getName());
            return generateCatchToken(jwtInfo);
        }
        throw new UserInvalidException("用户不存在或账户密码错误!");
    }
    
    /**
     * 设置缓存信息
     * @param jwtInfo
     * @return 
     */
    private String generateCatchToken(JWTInfo jwtInfo) {
    	String token = JwtTokenUtil.generateToken(jwtInfo, CacheConstant.ADMIN_USER_TOKEN_EXPIRE * 60);
    	log.debug("写入缓存：token=" + token);
    	cacheAPI.set(CacheConstant.ADMIN_USER_TOKEN_KEY + ":" + jwtInfo.getUniqueName() , token, CacheConstant.ADMIN_USER_TOKEN_EXPIRE);
    	return token;
    }
    
    @Override
    public boolean validate(String token) throws Exception {
    	JWTInfo jwtInfo = (JWTInfo)JwtTokenUtil.getInfoFromToken(token);
        log.debug("读取用户信息：" + JSON.toJSONString(jwtInfo));
        String strCatchToken = cacheAPI.get(CacheConstant.ADMIN_USER_TOKEN_KEY + ":" + jwtInfo.getUniqueName());
        //获取用户信息，可以把用户账号无效等状态加到业务处理
        if(StringUtils.isEmpty(strCatchToken)) {
            log.debug("写入缓存：token=" + token);
            strCatchToken = token;
            cacheAPI.set(CacheConstant.BASE_USER_TOKEN_KEY + ":" + jwtInfo.getUniqueName() , token, CacheConstant.BASE_USER_TOKEN_CATCH_EXPIRE);
        }
    	log.debug("读取缓存：token=" + strCatchToken);
    	//获取用户信息，可以把用户账号无效等状态加到业务处理
    	if(StringUtils.isEmpty(strCatchToken)) {
    		throw new BaseException(CommonConstants.TOKEN_ERROR_EXPIRE_CODE, CommonConstants.TOKEN_ERROR_EXPIRE_MSSSAGE);
    	}
    	if(!StringUtils.equals(token, strCatchToken)) {
    		throw new BaseException(CommonConstants.TOKEN_ERROR_EXISTS_CODE, CommonConstants.TOKEN_ERROR_EXISTS_MSSSAGE);
    	}
    	return true;
    }

    @Override
    public String refresh(String oldToken) throws Exception {
    	IJWTInfo jwtInfo = JwtTokenUtil.getInfoFromToken(oldToken);
        return JwtTokenUtil.generateToken(jwtInfo, CacheConstant.ADMIN_USER_TOKEN_EXPIRE);
    }
    
    @Override
    public User getMyInfo(String token) throws Exception {
        String username = JwtTokenUtil.getInfoFromToken(token).getUniqueName();
        if (username == null) {
    		throw new BaseException(CommonConstants.TOKEN_ERROR_CODE, CommonConstants.TOKEN_ERROR_MSSSAGE);
        }
        User user = userBiz.getUserByUsername(username);
        if(user == null) {
    		throw new BaseException(CommonConstants.STATUS_ERROR_CODE, "用户不存在");
        }
        return user;
    }

	@Override
	public void modifyMyInfo(String token, User user) throws Exception {
		// TODO Auto-generated method stub
        String username = JwtTokenUtil.getInfoFromToken(token).getUniqueName();
        if (username == null) {
    		throw new BaseException(CommonConstants.TOKEN_ERROR_CODE, CommonConstants.TOKEN_ERROR_MSSSAGE);
        }
        User searchUser = userBiz.getUserByUsername(username);
        if(searchUser == null) {
    		throw new BaseException(CommonConstants.STATUS_ERROR_CODE, "用户不存在");
        }
        if(!StringUtils.isEmpty(user.getName())) {
        	searchUser.setName(user.getName());
        }
        if(!StringUtils.isEmpty(user.getSex())) {
        	searchUser.setSex(user.getSex());
        }
        userBiz.updateSelectiveById(searchUser);
	}

	@Override
	public void modifyMyPassWord(String token, String oldPwd, String newPwd) throws Exception {
		// TODO Auto-generated method stub
		 String username = JwtTokenUtil.getInfoFromToken(token).getUniqueName();
		if (username == null) {
			throw new BaseException(CommonConstants.TOKEN_ERROR_CODE, CommonConstants.TOKEN_ERROR_MSSSAGE);
		}
		User searchUser = userBiz.getUserByUsername(username);
		if (searchUser == null) {
			throw new BaseException(CommonConstants.STATUS_ERROR_CODE, "用户不存在");
		}	
        String encoderNewPwd = new BCryptPasswordEncoder(UserConstant.PW_ENCORDER_SALT).encode(newPwd);
        if (!encoder.matches(oldPwd, searchUser.getPassword())) {
			throw new BaseException(CommonConstants.STATUS_ERROR_CODE, "当前密码错误");
        }
        searchUser.setPassword(encoderNewPwd);
        userBiz.updateSelectiveById(searchUser);
	}

	@Override
	public boolean checkUserName(String userName) throws Exception {
		// TODO Auto-generated method stub
		User user = userBiz.getUserByUsername(userName);
		if(user != null) {
			return true;
		}
		return false;
	}
}
